package org.bee.secuirty.Interceptor;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.bee.PageUtil;
import org.bee.ResultTool;
import org.bee.bean.BeanUtil;
import org.bee.enums.ResultCode;
import org.bee.exception.ExceptionUtils;
import org.bee.json.JsonUtils;
import org.bee.model.result.Result;
import org.bee.redis.RedisUtils;
import org.bee.secuirty.annotation.ApiAuth;
import org.bee.secuirty.annotation.TokenIgnore;
import org.bee.secuirty.context.CurrentUser;
import org.bee.secuirty.model.TokenInfo;
import org.bee.secuirty.model.UserInfo;
import org.bee.string.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;

/**
 * 认证授权拦截器
 */
public class TokenInterceptor implements HandlerInterceptor {
    Logger logger = LoggerFactory.getLogger(TokenInterceptor.class);

    /**
     * 内部调用token
     */
    @Value("${rpc.internalToken:#{null}}")
    private String internalToken;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Result result;
        String contextPath = request.getContextPath();
        if(contextPath.equals("/error")){
            return true;
        }
        //内部调用的密钥校验
        String authorization = request.getHeader("Bee-Internal-Auth");
        if(!StringUtils.isEmpty(authorization)){
            if(internalToken!=null&&internalToken.equals(authorization)){
                return true;
            }else {
                result = ResultTool.fail(ResultCode.INTERNAL_TOKEN_ERROR);
                response.setContentType("text/json;charset=utf-8");
                response.getWriter().write(Objects.requireNonNull(JsonUtils.toJson(result)));
                return false;
            }
        }

        RedisUtils redisUtils = BeanUtil.getBean("redisUtils", RedisUtils.class);
        boolean tokenIgnoreFlag = isIgnore(handler);
        // 需要认证的
        if (!tokenIgnoreFlag) {
            String tokeninfo = request.getHeader("Authorization");
            if(tokeninfo!=null){
                //获取到了token信息（已经登录过的）
                String bearer = tokeninfo.replace("Bearer ", "");
                String token = (String) redisUtils.get("LoginUserTokenInfo:"+bearer);
                if(StringUtils.isEmpty( token)){
                    //令牌失效或者不存在
                    try {
                        result = ResultTool.fail(ResultCode.TOKEN_ERROR);
                        response.setContentType("text/json;charset=utf-8");
                        response.getWriter().write(Objects.requireNonNull(JsonUtils.toJson(result)));
                    } catch (Exception e) {
                        logger.info("塞response失败{}", ExceptionUtils.getFullStackTrace(e));
                    }
                    return false;
                }else{
                    TokenInfo tokenInfo = JsonUtils.fromJson(token, TokenInfo.class);
                    if(null==tokenInfo){
                        result = ResultTool.fail(ResultCode.TOKEN_ERROR);
                        response.setContentType("text/json;charset=utf-8");
                        response.getWriter().write(Objects.requireNonNull(JsonUtils.toJson(result)));
                        return false;
                    }
                    List<String> userApis = tokenInfo.getUserApis();
                    //用户拥有的接口权限校验
                    boolean apiAuth = isApiAuth(handler, userApis);
                    if(!apiAuth){
                        result = ResultTool.fail(ResultCode.NO_PERMISSION);
                        response.setContentType("text/json;charset=utf-8");
                        response.getWriter().write(Objects.requireNonNull(JsonUtils.toJson(result)));
                        return false;
                    }
                    UserInfo userInfo = tokenInfo.getUserInfo();
                    userInfo.setToken(bearer);
                    CurrentUser.setUser(userInfo);
                    return true;
                }
            }else{
                //没有获取到token信息
                result = ResultTool.fail(ResultCode.USER_NOT_LOGIN);
                response.setContentType("text/json;charset=utf-8");
                response.getWriter().write(Objects.requireNonNull(JsonUtils.toJson(result)));
                return false;
            }
        } else {
            //不需要验证token
           return true;
        }
    }

    private boolean isIgnore(Object handler){
        if (handler instanceof HandlerMethod handlerMethod) {
            //获取当前controller的方法
            Method method = handlerMethod.getMethod();
            return method.isAnnotationPresent(TokenIgnore.class);
        }else{
            return false;
        }
    }

    private boolean isApiAuth(Object handler,List<String> userApis){
        HandlerMethod handlerMethod = (HandlerMethod)handler;
        //获取当前controller的方法
        Method method = handlerMethod.getMethod();
        //如果被ApiAuth注解标记
        if(method.isAnnotationPresent(ApiAuth.class)){
            ApiAuth apiAuth = method.getAnnotation(ApiAuth.class);
            String apiAuthsCode = apiAuth.value();
            return userApis.contains(apiAuthsCode);
        }else{
            return true;
        }
    }
    /**
     * ThreadLocal在线程结束的时候要清理，否则线程池可能会复用
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        CurrentUser.clearUser();
        PageUtil.clearPage();
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}
